// inotify示例程序
#include <limits.h>
#include <sys/inotify.h>
#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Display information from inotify_event structure
static void displayInotifyEvent(struct inotify_event *ev) {
    printf("    wd =%2d; ", ev->wd);
    if (ev->cookie > 0) {
        printf("cookie =%4d; ", ev->cookie);
    }

    printf("mask = ");
    if (ev->mask & IN_ACCESS) {
        printf("IN_ACCESS ");
    }
    if (ev->mask & IN_ATTRIB) {
        printf("IN_ATTRIB ");
    }
    if (ev->mask & IN_CLOSE_NOWRITE) {
        printf("IN_CLOSE_NOWRITE ");
    }
    if (ev->mask & IN_CLOSE_WRITE) {
        printf("IN_CLOSE_WRITE ");
    }
    if (ev->mask & IN_CREATE) {
        printf("IN_CREATE ");
    }
    if (ev->mask & IN_DELETE) {
        printf("IN_DELETE ");
    }
    if (ev->mask & IN_DELETE_SELF) {
        printf("IN_DELETE_SELF ");
    }
    if (ev->mask & IN_IGNORED) {
        printf("IN_IGNORED ");
    }
    if (ev->mask & IN_ISDIR) {
        printf("IN_ISDIR ");
    }
    if (ev->mask & IN_MODIFY) {
        printf("IN_MODIFY ");
    }
    if (ev->mask & IN_MOVED_FROM) {
        printf("IN_MOVED_FROM ");
    }
    if (ev->mask & IN_MOVED_TO) {
        printf("IN_MOVED_TO ");
    }
    if (ev->mask & IN_OPEN) {
        printf("IN_OPEN ");
    }
    if (ev->mask & IN_Q_OVERFLOW) {
        printf("IN_Q_OVERFLOW ");
    }
    if (ev->mask & IN_UNMOUNT) {
        printf("IN_UNMOUNT ");
    }
    printf("\n");

    if (ev->len > 0) {
        printf("        name = %s\n", ev->name);
    }
}

#define BUF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1))

int main(int argc, char *argv[]) {
    if (argc < 2 || strcmp(argv[1], "--help") == 0) {
        fprintf(stderr, "%s pathname...\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // Create inotify instance
    int inotifyFD = inotify_init();
    if (inotifyFD == -1) {
        perror("inotify_init");
        exit(EXIT_FAILURE);
    }

    // Add watch file or directory
    for (int i = 1; i < argc; i++) {
        int wd = inotify_add_watch(inotifyFD, argv[i], IN_ALL_EVENTS);
        if (wd == -1) {
            perror("inotify_add_watch");
            exit(EXIT_FAILURE);
        }

        printf("Watching %s using wd %d\n", argv[i], wd);
    }

    // Read events forever
    char buf[BUF_LEN];
    for (;;) {
        ssize_t numRead = read(inotifyFD, buf, BUF_LEN);
        if (numRead == 0) {
            fprintf(stderr, "read() from inotify fd returned 0!");
            exit(EXIT_FAILURE);
        }

        if (numRead == -1) {
            perror("read");
            exit(EXIT_FAILURE);
        }

        printf("Read %ld bytes from inotify fd\n", (long)numRead);

        // Process all of the events in buffer returned by read()
        for (char *p = buf; p < buf + numRead;) {
            struct inotify_event *event = (struct inotify_event *)p;
            displayInotifyEvent(event);
            p += sizeof(struct inotify_event) + event->len;
        }
    }

    exit(EXIT_SUCCESS);
}
